/* $Id: ContestEntry.java 138 2011-09-01 17:51:37Z altdotua@gmail.com $ */

package alt.djudge.frontend.server.datatypes;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import alt.djudge.frontend.server.models.ContestLanguagesModel;
import alt.djudge.frontend.server.models.ContestProblemsModel;
import alt.djudge.frontend.server.models.ContestUsersModel;
import alt.djudge.frontend.server.models.SubmissionsModel;
import alt.djudge.frontend.server.utils.Formatters;
import alt.djudge.frontend.shared.dto.admin.ContestEntryDTO;
import alt.djudge.frontend.shared.dto.admin.AdminDTOEntry;
import alt.djudge.frontend.shared.dto.contest.ContestInfoDTO;


@PersistenceCapable(detachable="true")
public class ContestEntry extends AbstractEntry
{
	private static final long serialVersionUID = 1L;
	
	@PrimaryKey
	@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	protected Long id;
	
	@Override
	public Long getId()
	{
		return id;
	}
	
	@Override
	public void setId(Long id)
	{
		this.id = id;
	}
	
	// short name
	@Persistent
	private String sid = "-";

	// full name
	@Persistent
	private String name = "-";
	
	// start time
	@Persistent
	private Date startTime = new Date();	
	
	// finish time 
	@Persistent
	private Date finishTime = new Date();
	
	// freeze time
	@Persistent
	private Date freezeTime = new Date();	
	
	@Persistent
	private Date unfreezeTime = new Date();	
	
	@Persistent
	private String contestType = "acm";
	
	@Persistent
	private Long userId = 1L;
	
	@Persistent
	private Boolean allowAllLanguages = true;
	
	@Persistent
	private Boolean allowAllUsers = true;
	
	@Persistent
	private Boolean allowFirstTestOnly = true;
	
	@Persistent
	private Long contestDuration = 1000000L;
	
	@Persistent
	private Boolean showFullMonitor = true;
	
	@Persistent
	private Boolean showFullSubmissions = true;
	
	@Persistent
	private Boolean showWrongTest = true;
	
	@Persistent
	private Boolean showMaxTime = true;
	
	@Persistent
	private Boolean showMaxMemory = true;
	
	@Persistent
	private Boolean showMaxOutput = true;
	
	@Persistent
	private Boolean showTestingDetails = true;
	
	@Persistent
	private Boolean showScore = true;
	
	@Persistent
	private String statementsLink;
	
	@Persistent
	private Boolean virtual = false;
	
	public String getSid()
	{
		return sid;
	}
	
	public void setSid(String sid)
	{
		this.sid = sid;
	}
	
	public String getName()
	{
		return name;
	}

	
	public void setName(String name)
	{
		this.name = name;
	}

	public Date getStartTime()
	{
		return startTime;
	}

	
	public void setStartTime(Date startTime)
	{
		this.startTime = startTime;
	}

	
	public Date getFreezeTime()
	{
		return freezeTime;
	}

	
	public void setFreezeTime(Date freezeTime)
	{
		this.freezeTime = freezeTime;
	}

	
	public Date getFinishTime()
	{
		return finishTime;
	}

	
	public void setFinishTime(Date finishTime)
	{
		this.finishTime = finishTime;
	}
	
	public void setUserId(Long userId)
	{
		this.userId = userId;
	}


	public Long getUserId()
	{
		return userId;
	}
	
	public String toString()
	{
		return name;
	}


	public void setContestType(String contestType)
	{
		this.contestType = contestType;
	}


	public String getContestType()
	{
		return contestType;
	}

	public void setAllowAllLanguages(Boolean allowAllLanguages)
	{
		this.allowAllLanguages = allowAllLanguages;
	}

	public Boolean getAllowAllLanguages()
	{
		return allowAllLanguages;
	}


	public void setAllowAllUsers(Boolean allowAllUsers)
	{
		this.allowAllUsers = allowAllUsers;
	}


	public Boolean getAllowAllUsers()
	{
		return allowAllUsers;
	}


	public void setContestDuration(Long contestDuration)
	{
		this.contestDuration = contestDuration;
	}


	public Long getContestDuration()
	{
		return contestDuration;
	}


	public void setVirtual(Boolean virtual)
	{
		this.virtual = virtual;
	}


	public Boolean getVirtual()
	{
		return virtual;
	}


	public void setShowFullMonitor(Boolean showFullMonitor)
	{
		this.showFullMonitor = showFullMonitor;
	}


	public Boolean getShowFullMonitor()
	{
		return showFullMonitor;
	}


	public void setShowFullSubmissions(Boolean showFullSubmissions)
	{
		this.showFullSubmissions = showFullSubmissions;
	}


	public Boolean getShowFullSubmissions()
	{
		return showFullSubmissions != null ? showFullSubmissions : true;
	}


	public void setShowWrongTest(Boolean showWrongTest)
	{
		this.showWrongTest = showWrongTest;
	}


	public Boolean getShowWrongTest()
	{
		return showWrongTest;
	}


	public void setShowMaxMemory(Boolean showMaxMemory)
	{
		this.showMaxMemory = showMaxMemory;
	}


	public Boolean getShowMaxMemory()
	{
		return showMaxMemory;
	}


	public void setShowMaxTime(Boolean showMaxTime)
	{
		this.showMaxTime = showMaxTime;
	}


	public Boolean getShowMaxTime()
	{
		return showMaxTime;
	}


	public void setShowTestingDetails(Boolean showTestingDetails)
	{
		this.showTestingDetails = showTestingDetails;
	}


	public Boolean getShowTestingDetails()
	{
		return showTestingDetails;
	}


	public void setShowScore(Boolean showScore)
	{
		this.showScore = showScore;
	}


	public Boolean getShowScore()
	{
		return showScore;
	}


	public void setAllowFirstTestOnly(Boolean allowFirstTestOnly)
	{
		this.allowFirstTestOnly = allowFirstTestOnly;
	}

	public Boolean getAllowFirstTestOnly()
	{
		return allowFirstTestOnly;
	}
	
	@Override
	public void clearCacheCustom()
	{
		//String key = CacheModel.getEntryBySidKey(getClass(), getSid());
		//String keyLangList = CacheModel.getContestLanguagesKey(getId().toString());
		//CacheModel.getStaticCache().remove(key);
		//CacheModel.getStaticCache().remove(keyLangList);
	}

	public boolean isStarted(UserEntry user)
	{
		// TODO: implement later
		if (getVirtual())
		{
			return false;
		}
		return getStartTime().before(new Date());
	}


	public boolean isFinished(UserEntry user)
	{
		// TODO: implement later
		if (getVirtual())
		{
			return false;
		}
		return getFinishTime().before(new Date());
	}


	public boolean isAdmin(UserEntry user)
	{
		return user.isAdmin();
	}
	
	public String getState()
	{
		Date now = new Date();
		if (getStartTime().after(now))
			return "Змагання не почалось";
		if (getFinishTime().before(now))
			return "Змагання закінчилось";
		if (getFinishTime().after(now))
				return "Змагання триває";
		return "Unknown";
	}
	
	public String getContestTimeString()
	{
		Date now = new Date();
		if (getStartTime().after(now))
			return "-";
		if (getFinishTime().before(now))
			return Formatters.formatContestTime((getFinishTime().getTime() - getStartTime().getTime()) / 60000);
		Long sec = (now.getTime() - getStartTime().getTime()) / 1000; 
		return Formatters.formatContestTimeSeconds(sec);
	}
	
	public Boolean isAuthorizedUser(UserEntry user)
	{
		if (getAllowAllUsers() || user.isAdmin())
			return true;
		return ContestUsersModel.getEntry(getId(), user.getId()) != null;
	}

	// seconds
	public Long getContestTime(ContestUserEntry user)
	{
		// TODO: fixme
		Date now = new Date();
		if (now.before(getStartTime()))
			return 0L;
		if (now.after(getFinishTime()))
			return (getFinishTime().getTime() - getStartTime().getTime()) / 1000;
		return (now.getTime() - getStartTime().getTime()) / 1000;
	}


	public void setStatementsLink(String statementsLink)
	{
		this.statementsLink = statementsLink;
	}


	public String getStatementsLink()
	{
		return statementsLink;
	}


	public void setUnfreezeTime(Date unfreezeTime)
	{
		this.unfreezeTime = unfreezeTime;
	}


	public Date getUnfreezeTime()
	{
		return unfreezeTime;
	}
	
	public void setShowMaxOutput(Boolean showMaxOutput)
	{
		this.showMaxOutput = showMaxOutput;
	}


	public Boolean getShowMaxOutput()
	{
		return showMaxOutput;
	}
	
	public boolean isDefault()
	{
		return "DEFAULT".equalsIgnoreCase(getSid());
	}

	public boolean clearProblems()
	{
		if (!crearSubmissions())
			return false;
		
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("contestId", this.getId());
		List<ContestProblemEntry> entries = ContestProblemsModel.getEntries(map);
		for (ContestProblemEntry entry: entries)
			if (!entry.delete())
				return false; 
		return true;
	}

	public boolean clearUsers()
	{
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("contestId", this.getId());
		List<ContestUserEntry> entries = ContestUsersModel.getEntries(map);
		for (ContestUserEntry entry: entries)
			if (!entry.delete())
				return false;
		return true;
	}


	public boolean clearLanguages()
	{
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("contestId", this.getId());
		List<ContestLanguageEntry> entries = ContestLanguagesModel.getEntries(map);
		for (ContestLanguageEntry entry: entries)
			if (!entry.delete())
				return false;
		return true;
	}


	public boolean crearSubmissions()
	{
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("contestId", this.getId());
		List<SubmissionEntry> entries = SubmissionsModel.getSubmissions(map);
		for (SubmissionEntry entry: entries)
			if (!entry.delete())
				return false;
		return true;
	}

	public boolean rejudgeSubmissions()
	{
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("contestId", this.getId());
		map.put("order", "id ASC");
		List<SubmissionEntry> entries = SubmissionsModel.getSubmissions(map);
		for (SubmissionEntry entry: entries)
		{
			entry.prepareForRejudge();
			if (!entry.makePersistent())
				return false;
		}
		return true;
	}
	
	public boolean isRunning(UserEntry user)
	{
		return isStarted(user) && !isFinished(user);
	}

	public ContestEntry()
	{
		// TODO Auto-generated constructor stub
	}

	public ContestEntry(ContestEntryDTO dtoEntry)
	{
		fromDTO(dtoEntry);
	}
	
	@Override
	public void fromDTO(AdminDTOEntry dtoEntry)
	{
		setSid(dtoEntry.getFieldValue(1));
		setName(dtoEntry.getFieldValue(2));
	}
	
	@Override
	public ContestEntryDTO ownAdminDTO()
	{
		ContestEntryDTO entry = new ContestEntryDTO(new String[] {
				"" + getId(),
				getSid(),
				getName(),
		});
		return entry;
	}
	
	public ContestInfoDTO asContestInfoDTO()
	{
		ContestInfoDTO contestInfoDTO = new ContestInfoDTO();
		ContestEntry contest = this;
		contestInfoDTO.setId(contest.getId());
		contestInfoDTO.setAllowAllLanguages(contest.getAllowAllLanguages());
		contestInfoDTO.setAllowAllUsers(contest.getAllowAllLanguages());
		contestInfoDTO.setContestDuration(contest.getContestDuration());
		contestInfoDTO.setFinishTime(contest.getFinishTime());
		contestInfoDTO.setFreezeTime(contest.getFinishTime());
		contestInfoDTO.setName(contest.getName());
		contestInfoDTO.setSid(contest.getSid());
		contestInfoDTO.setStartTime(contest.getStartTime());
		contestInfoDTO.setStatementsLink(contest.getStatementsLink());
		contestInfoDTO.setUnfreezeTime(contest.getUnfreezeTime());
		contestInfoDTO.setUserId(contest.getUserId());
		contestInfoDTO.setVirtual(contest.getVirtual());
		return contestInfoDTO;
	}

	public int submitSolution(UserEntry user, Long contestProblemId,
			Long languageId, String sourceCode)
	{
		// TODO Auto-generated method stub
		return 0;
	}
}
